package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackRequest;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.stack.mac.type.DataAddress;
import com.meshnetics.gb.stack.mac.type.TxOptions;
import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.Str;
import com.meshnetics.gb.type.impl.zcl.TypeStr;
import com.meshnetics.gb.type.impl.zcl.TypeUInt;
import com.meshnetics.gb.type.impl.zcl.UInt;
import com.meshnetics.gb.util.ToStringUtil;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACDataRequest extends StackRequest implements MACCommand, MACReplyAwaited {
    public static final byte CODE = 0x40;

    private final DataAddress srcAddr;
    private final DataAddress dstAddr;
    private final UInt msduLength;
    private final Str msdu;
    private final UInt msduHandle;
    private final TxOptions txOptions;

    public MACDataRequest(DataAddress srcAddr, DataAddress dstAddr, byte[] msdu, int msduHandle, TxOptions txOptions) {
        this(srcAddr, dstAddr, msdu, (byte) (msduHandle & 0xff), txOptions);
    }

    public MACDataRequest(DataAddress srcAddr, DataAddress dstAddr, byte[] msdu, byte msduHandle, TxOptions txOptions) {
        this(srcAddr, dstAddr, msdu, new Byte(msduHandle), txOptions);
    }

    public MACDataRequest(DataAddress srcAddr, DataAddress dstAddr, byte[] msdu, Byte msduHandle, TxOptions txOptions) {
        this(srcAddr, dstAddr, (Str) TypeStr.STRING_OCTET.fromObject(msdu),
                (UInt) TypeUInt.UINT_8.fromObject(msduHandle), txOptions);
    }

    public MACDataRequest(DataAddress srcAddr, DataAddress dstAddr, Str msdu, UInt msduHandle, TxOptions txOptions) {
        super("macDataRequest", StackEventType.LDE_TYPE);
        if (srcAddr == null) {
            throw new NullPointerException("srcAddr is null");
        }
        if (dstAddr == null) {
            throw new NullPointerException("dstAddr is null");
        }
        if (msdu == null) {
            throw new NullPointerException("msdu is null");
        }
        if (msduHandle == null) {
            throw new NullPointerException("msduHandle is null");
        }
        if (txOptions == null) {
            throw new NullPointerException("txOptions is null");
        }
        if (!TypeStr.STRING_OCTET.equals(msdu.getType())) {
            throw new IllegalArgumentException("msdu is not an octet string");
        }
        this.srcAddr = srcAddr;
        this.dstAddr = dstAddr;
        this.msduLength = (UInt) TypeUInt.UINT_8.fromObject(new Integer(msdu.getOctetLength()));
        int check = ((Number) msduLength.toObject()).intValue();
        if (check < 0 || check > 102) {
            throw new IllegalArgumentException("invalid msduLength");
        }
        this.msdu = msdu;
        this.msduHandle = msduHandle.convert(TypeUInt.UINT_8);
        this.txOptions = txOptions;
    }

    public DataAddress getSrcAddr() {
        return srcAddr;
    }

    public DataAddress getDstAddr() {
        return dstAddr;
    }

    public UInt getMsduLengthType() {
        return msduLength;
    }

    public Str getMsduType() {
        return msdu;
    }

    public UInt getMsduHandleType() {
        return msduHandle;
    }

    public Byte getMsduLength() {
        return (Byte) msduLength.toObject();
    }

    public byte[] getMsdu() {
        return (byte[]) msdu.toObject();
    }

    public Byte getMsduHandle() {
        return (Byte) msduHandle.toObject();
    }

    public TxOptions getTxOptions() {
        return txOptions;
    }

    public byte getCode() {
        return CODE;
    }

    public int getSize(RadioMACStackLayer layer) {
        return srcAddr.getDataSize() + dstAddr.getDataSize() + 1 + ((Number) msduLength.toObject()).intValue() + 2;
    }

    public void serialize(ByteBuffer bb, RadioMACStackLayer layer) {
        ByteUtils.ensureNotNull(bb);
        srcAddr.serialize(bb);
        dstAddr.serialize(bb);
        msduLength.serialize(bb);
        msdu.serializeWithoutLength(bb, false);
        msduHandle.serialize(bb);
        txOptions.serialize(bb);
    }

    public String toString() {
        return getName() + " id = " + ToStringUtil.toHexString(getID()) + "( macHandle= " + msduHandle +
                ", src= " + srcAddr + ", dst= " + dstAddr + "len= " + msduLength + ", msdu= " + msdu +
                ", " + txOptions + ')';
    }
}
